package MathCore;

import java.util.Enumeration;
import java.util.Stack;
import java.util.Vector;
import MathCore.Operators.Function;

public class Expression extends Object
{
    private Lexeme first=null, last=null;
    private int lenght=0;

    public static final int TYPE_INFIX=0, TYPE_RPN=1;
    private int type = TYPE_INFIX;

    public Expression(int type)
    {
	    this.type = type;
    }

    public Expression(Expression orig)
    {
	    this.type = orig.type;
	    for(Lexeme l = orig.first(); l != null; l = l.next)
	    {
		    add(l.clone());
	    }
    }

    public String toString()
    {
		StringBuffer buf = new StringBuffer();

		for(Lexeme l = first(); l != null; l = l.next)
		{
			buf.append(l.toString());
			buf.append(' ');
		}

		return buf.toString();
    }

    public int size()
    {
	    return lenght;
    }

    public Lexeme first()
    {
	    return first;
    }

	public Lexeme last()
	{
		return last;
	}

	public int getIndex(Lexeme obj)
	{
		int counter = 0;
		for(Lexeme lex = first(); lex != null; lex = lex.next, counter++)
		{
			if(lex == obj) return counter;
		}

		return -1;
	}

    public Lexeme add(Lexeme l)
    {
	    if(l == null) return null;
		l.next = l.prev = null;

		if(lenght == 0) first = l;
	    else if(lenght == 1)
	    {
			last = l;
			first.next = last;
			last.prev = first;
	    }
	    else
	    {
			l.prev = last;
			last.next = l;
			last = l;
	    }

	    lenght++;

	    return l;
    }

    public Lexeme remove(Lexeme l)
    {
	    if(l == null) return null;

		if(lenght == 1) last = first = null;

	    if(l.next != null && l.prev != null) // somewhere in middle
	    {
			l.prev.next = l.next;
			l.next.prev = l.prev;
	    }
	    else if(l.next != null && l.prev == null) // first in list
	    {
			first = l.next;
			first.prev = null;
	    }
	    else // end of expression
	    {
			last = l.prev;
			if(last != null) last.next = null;
	    }
	    
	    lenght--;

	    return l;
	}

	public void clear()
	{
	    if(first == null) return;

	    Lexeme l = first, l2;
	    while(l.next != null)
	    {
			l2 = l.next;
			l.next = null;
			l = l2;
	    }

	    first = null;
	    last = null;
	    lenght = 0;
	}

	public int getType()
	{
		return type;
	}

	public boolean empty()
	{
		return lenght == 0 ? true : false;
	}

	public Lexeme insertAfter(Lexeme newlex, Lexeme pivot)
	{
		if(newlex == null) return null;

		if(pivot == null)
		{
			newlex.next = first;
			first.prev = newlex;
			first = newlex;

			lenght++;
			return newlex;
		}
		
		if(!isMember(pivot)) return null;

		else if(pivot == last || size()==1) return add(newlex);
		else
		{
			Lexeme left = pivot, right = pivot.next;
			if(left != null) left.next = newlex;
			if(right != null) right.prev = newlex;
			newlex.next = right;
			newlex.prev = left;

			lenght++;
			return newlex;
		}
	}

	private boolean isMember(Lexeme lex)
	{
		for(Lexeme l = first; l != null; l = l.next) if(lex == l) return true;
		return false;
	}

	public void dbg_trace()
	{
		String s;
		System.out.println("Trace start");
		for(Lexeme l = first; l != null; l = l.next)
		{
			s="";

			if(l.prev == null) s += "null";
			else { s += l.prev.toString(); }

			s+=" <- " + l.toString() + " -> ";

			if(l.next == null) s += "null";
			else { s += l.next.toString(); }

			System.out.println("\t"+s);
		}

		if(first == null) System.out.println("\tfirst: null");
		else System.out.println("\tfirst: "+first);

		if(last == null) System.out.println("\tlast: null");
		else System.out.println("\tlast: "+last);

		System.out.println("\tlenght: "+lenght);
		
		System.out.println("Trace complete");
	}
}
